#include "keyframeinformation.h"
#include "global.h"
#include "enums.h"

void KeyFrameInformation::setFrameNumber(int fn) { m_frameNumber = fn; }
void KeyFrameInformation::setPosition(Vec pos) { m_position = pos; }
void KeyFrameInformation::setOrientation(Quaternion rot) { m_rotation = rot; }
void KeyFrameInformation::setVolumeBounds(Vec bmin, Vec bmax) { m_volMin = bmin; m_volMax = bmax; }
void KeyFrameInformation::set4dInfo(Vec bs4d, int ts) { m_boxsize4d = bs4d; m_timestep = ts; }
void KeyFrameInformation::setImage(QImage pix) { m_image = pix; }
void KeyFrameInformation::setLut(float* lut)
{
  if (!m_lut)
    m_lut = new float[Global::lutSize()*256*256*4];
  memcpy(m_lut, lut, Global::lutSize()*256*256*4);
}
void KeyFrameInformation::setSplineInfo(QList<SplineInformation> si) { m_splineInfo = si; }
void KeyFrameInformation::setMorphTF(bool flag) { m_morphTF = flag; }
void KeyFrameInformation::setClipInfo(ClipInformation ci) { m_clipInfo = ci; }
void KeyFrameInformation::setLightInfo(LightingInformation li) { m_lightInfo = li; }



int KeyFrameInformation::frameNumber() { return m_frameNumber; }
Vec KeyFrameInformation::position() { return m_position; }
Quaternion KeyFrameInformation::orientation() { return m_rotation; }
void KeyFrameInformation::volumeBounds(Vec &bmin, Vec &bmax) { bmin = m_volMin; bmax = m_volMax; }
void KeyFrameInformation::get4dInfo(Vec &bs4d, int &ts) { bs4d = m_boxsize4d; ts = m_timestep; }
QImage KeyFrameInformation::image() { return m_image; }
float* KeyFrameInformation::lut() { return m_lut; }
QList<SplineInformation> KeyFrameInformation::splineInfo() { return m_splineInfo; }
bool KeyFrameInformation::morphTF() { return m_morphTF; }
ClipInformation KeyFrameInformation::clipInfo() { return m_clipInfo; }
LightingInformation KeyFrameInformation::lightInfo() { return m_lightInfo; }



// -- keyframe interpolation parameters
void KeyFrameInformation::setInterpVolumeBounds(int i) {m_interpVolumeBounds = i;}
void KeyFrameInformation::setInterpCameraPosition(int i) {m_interpCameraPosition = i;}
void KeyFrameInformation::setInterpCameraOrientation(int i) {m_interpCameraOrientation = i;}
void KeyFrameInformation::setInterpTF(int i) {m_interpTF = i;}
void KeyFrameInformation::setInterpClipInfo(int i) {m_interpClipInfo = i;}
void KeyFrameInformation::setInterpLightInfo(int i) {m_interpLightInfo = i;}



int KeyFrameInformation::interpVolumeBounds() { return m_interpVolumeBounds; }
int KeyFrameInformation::interpCameraPosition() { return m_interpCameraPosition; }
int KeyFrameInformation::interpCameraOrientation() { return m_interpCameraOrientation; }
int KeyFrameInformation::interpTF() { return m_interpTF; }
int KeyFrameInformation::interpClipInfo() { return m_interpClipInfo; }
int KeyFrameInformation::interpLightInfo() { return m_interpLightInfo; }



KeyFrameInformation::KeyFrameInformation()
{
  m_frameNumber = 0;
  m_position = Vec(0,0,0);
  m_rotation = Quaternion(Vec(1,0,0), 0);
  m_volMin = m_volMax = Vec(0,0,0);
  m_boxsize4d = Vec(0,0,0);
  m_timestep = -1;
  m_image = QImage(100, 100, QImage::Format_RGB32);
  m_lut = 0;
  m_splineInfo.clear();
  m_morphTF = false;
  m_clipInfo.clear();
  m_lightInfo.clear();

  m_interpVolumeBounds = Enums::KFIT_Linear;
  m_interpCameraPosition = Enums::KFIT_Linear;
  m_interpCameraOrientation = Enums::KFIT_Linear;
  m_interpTF = Enums::KFIT_Linear;
  m_interpClipInfo = Enums::KFIT_Linear;
  m_interpLightInfo = Enums::KFIT_Linear;
}

void
KeyFrameInformation::clear()
{
  m_frameNumber = 0;
  m_position = Vec(0,0,0);
  m_rotation = Quaternion(Vec(1,0,0), 0);
  m_volMin = m_volMax = Vec(0,0,0);
  m_boxsize4d = Vec(0,0,0);
  m_timestep = -1;
  m_image = QImage(100, 100, QImage::Format_RGB32);
  if (m_lut) delete [] m_lut;
  m_lut = 0;
  m_splineInfo.clear();
  m_morphTF = false;
  m_clipInfo.clear();
  m_lightInfo.clear();

  m_interpVolumeBounds = Enums::KFIT_Linear;
  m_interpCameraPosition = Enums::KFIT_Linear;
  m_interpCameraOrientation = Enums::KFIT_Linear;
  m_interpTF = Enums::KFIT_Linear;
  m_interpClipInfo = Enums::KFIT_Linear;
  m_interpLightInfo = Enums::KFIT_Linear;
}

KeyFrameInformation::KeyFrameInformation(const KeyFrameInformation& kfi)
{
  m_frameNumber = kfi.m_frameNumber;

  m_position = kfi.m_position;
  m_rotation = kfi.m_rotation;

  m_volMin = kfi.m_volMin;
  m_volMax = kfi.m_volMax;

  m_boxsize4d = kfi.m_boxsize4d;
  m_timestep = kfi.m_timestep;

  m_image = kfi.m_image;

  if (!m_lut)
    m_lut = new float[Global::lutSize()*256*256*4];
  memcpy(m_lut, kfi.m_lut, Global::lutSize()*256*256*4);

  m_splineInfo = kfi.m_splineInfo;
  m_morphTF = kfi.m_morphTF;

  m_clipInfo = kfi.m_clipInfo;
  m_lightInfo = kfi.m_lightInfo;

  m_interpVolumeBounds = kfi.m_interpVolumeBounds;
  m_interpCameraPosition = kfi.m_interpCameraPosition;
  m_interpCameraOrientation = kfi.m_interpCameraOrientation;
  m_interpTF = kfi.m_interpTF;
  m_interpClipInfo = kfi.m_interpClipInfo;
  m_interpLightInfo = kfi.m_interpLightInfo;
}

KeyFrameInformation::~KeyFrameInformation()
{
  if (m_lut) delete [] m_lut;
  m_lut = 0;
  m_splineInfo.clear();
  m_clipInfo.clear();
  m_lightInfo.clear();
}

KeyFrameInformation&
KeyFrameInformation::operator=(const KeyFrameInformation& kfi)
{
  m_frameNumber = kfi.m_frameNumber;

  m_position = kfi.m_position;
  m_rotation = kfi.m_rotation;

  m_volMin = kfi.m_volMin;
  m_volMax = kfi.m_volMax;

  m_boxsize4d = kfi.m_boxsize4d;
  m_timestep = kfi.m_timestep;

  m_image = kfi.m_image;

  if (!m_lut)
    m_lut = new float[Global::lutSize()*256*256*4];
  memcpy(m_lut, kfi.m_lut, Global::lutSize()*256*256*4);

  m_splineInfo = kfi.m_splineInfo;
  m_morphTF = kfi.m_morphTF;

  m_clipInfo = kfi.m_clipInfo;
  m_lightInfo = kfi.m_lightInfo;

  m_interpVolumeBounds = kfi.m_interpVolumeBounds;
  m_interpCameraPosition = kfi.m_interpCameraPosition;
  m_interpCameraOrientation = kfi.m_interpCameraOrientation;
  m_interpTF = kfi.m_interpTF;
  m_interpClipInfo = kfi.m_interpClipInfo;
  m_interpLightInfo = kfi.m_interpLightInfo;

  return *this;
}

//--------------------------------
//---- load and save -------------
//--------------------------------

void
KeyFrameInformation::load(fstream &fin)
{
  bool done = false;
  char keyword[100];

  m_interpVolumeBounds = Enums::KFIT_Linear;
  m_interpCameraPosition = Enums::KFIT_Linear;
  m_interpCameraOrientation = Enums::KFIT_Linear;
  m_interpTF = Enums::KFIT_Linear;
  m_interpClipInfo = Enums::KFIT_Linear;
  m_interpLightInfo = Enums::KFIT_Linear;

  while (!done)
    {
      fin.getline(keyword, 100, 0);

      if (strcmp(keyword, "keyframeend") == 0)
	done = true;
      else if (strcmp(keyword, "framenumber") == 0)
	fin.read((char*)&m_frameNumber, sizeof(int));
      else if (strcmp(keyword, "boxsize4d") == 0)
	fin.read((char*)&m_boxsize4d, 3*sizeof(float));
      else if (strcmp(keyword, "timestep") == 0)
	fin.read((char*)&m_timestep, sizeof(int));
      else if (strcmp(keyword, "volmin") == 0)
	fin.read((char*)&m_volMin, 3*sizeof(float));
      else if (strcmp(keyword, "volmax") == 0)
	fin.read((char*)&m_volMax, 3*sizeof(float));
      else if (strcmp(keyword, "position") == 0)
	fin.read((char*)&m_position, 3*sizeof(float));
      else if (strcmp(keyword, "rotation") == 0)
	{
	  Vec axis;
	  float angle;
	  fin.read((char*)&axis, 3*sizeof(float));
	  fin.read((char*)&angle, sizeof(float));
	  m_rotation.setAxisAngle(axis, angle);
	}
      else if (strcmp(keyword, "image") == 0)
	{
	  int n;
	  fin.read((char*)&n, sizeof(int));
	  unsigned char *tmp = new unsigned char[n+1];
	  fin.read((char*)tmp, n);
	  m_image = QImage::fromData(tmp, n);	 
	  delete [] tmp;
	}
      else if (strcmp(keyword, "lookuptable") == 0)
	{
	  if (!m_lut)
	    m_lut = new float[Global::lutSize()*256*256*4];
	  int n;
	  fin.read((char*)&n, sizeof(int));
	  n = qMin(n, Global::lutSize());
	  fin.read((char*)m_lut, n*256*256*4*sizeof(float));
	}
      else if (strcmp(keyword, "splineinfostart") == 0)
	{
	  SplineInformation splineInfo;
	  splineInfo.load(fin);
	  m_splineInfo.append(splineInfo);
	}
      else if (strcmp(keyword, "morphtf") == 0)
	fin.read((char*)&m_morphTF, sizeof(bool));
      else if (strcmp(keyword, "clipinformation") == 0)
	m_clipInfo.load(fin);
      else if (strcmp(keyword, "lightinginformation") == 0)
	m_lightInfo.load(fin);
      else if (strcmp(keyword, "interpvolumebounds") == 0)
	fin.read((char*)&m_interpVolumeBounds, sizeof(int));
      else if (strcmp(keyword, "interpcamerapos") == 0)
	fin.read((char*)&m_interpCameraPosition, sizeof(int));
      else if (strcmp(keyword, "interpcamerarot") == 0)
	fin.read((char*)&m_interpCameraOrientation, sizeof(int));
      else if (strcmp(keyword, "interptf") == 0)
	fin.read((char*)&m_interpTF, sizeof(int));
      else if (strcmp(keyword, "interpclipinfo") == 0)
	fin.read((char*)&m_interpClipInfo, sizeof(int));
      else if (strcmp(keyword, "interplightinfo") == 0)
	fin.read((char*)&m_interpLightInfo, sizeof(int));
    }
}

void
KeyFrameInformation::save(fstream &fout)
{
  char keyword[100];

  memset(keyword, 0, 100);
  sprintf(keyword, "keyframestart");
  fout.write((char*)keyword, strlen(keyword)+1);


  memset(keyword, 0, 100);
  sprintf(keyword, "framenumber");
  fout.write((char*)keyword, strlen(keyword)+1);
  fout.write((char*)&m_frameNumber, sizeof(int));


  memset(keyword, 0, 100);
  sprintf(keyword, "boxsize4d");
  fout.write((char*)keyword, strlen(keyword)+1);
  fout.write((char*)&m_boxsize4d, 3*sizeof(float));


  memset(keyword, 0, 100);
  sprintf(keyword, "timestep");
  fout.write((char*)keyword, strlen(keyword)+1);
  fout.write((char*)&m_timestep, sizeof(int));


  memset(keyword, 0, 100);
  sprintf(keyword, "volmin");
  fout.write((char*)keyword, strlen(keyword)+1);
  fout.write((char*)&m_volMin, 3*sizeof(float));


  memset(keyword, 0, 100);
  sprintf(keyword, "volmax");
  fout.write((char*)keyword, strlen(keyword)+1);
  fout.write((char*)&m_volMax, 3*sizeof(float));


  memset(keyword, 0, 100);
  sprintf(keyword, "position");
  fout.write((char*)keyword, strlen(keyword)+1);
  fout.write((char*)&m_position, 3*sizeof(float));


  memset(keyword, 0, 100);
  sprintf(keyword, "rotation");
  fout.write((char*)keyword, strlen(keyword)+1);
  Vec axis;
  float angle;
  m_rotation.getAxisAngle(axis, angle);
  fout.write((char*)&axis, 3*sizeof(float));
  fout.write((char*)&angle, sizeof(float));


  memset(keyword, 0, 100);
  sprintf(keyword, "image");
  fout.write((char*)keyword, strlen(keyword)+1);
  QByteArray bytes;
  QBuffer buffer(&bytes);
  buffer.open(QIODevice::WriteOnly);
  m_image.save(&buffer, "PNG");
  int n = bytes.size();
  fout.write((char*)&n, sizeof(int));
  fout.write((char*)bytes.data(), n);

  if (m_lut)
    {
      memset(keyword, 0, 100);
      sprintf(keyword, "lookuptable");
      fout.write((char*)keyword, strlen(keyword)+1);
      int n = Global::lutSize();
      fout.write((char*)&n, sizeof(int));
      fout.write((char*)m_lut, Global::lutSize()*256*256*4*sizeof(float));
    }

  for(int i=0; i<m_splineInfo.size(); i++)
    m_splineInfo[i].save(fout);

  memset(keyword, 0, 100);
  sprintf(keyword, "morphtf");
  fout.write((char*)keyword, strlen(keyword)+1);
  fout.write((char*)&m_morphTF, sizeof(bool));
  
  m_clipInfo.save(fout);
  m_lightInfo.save(fout);

  //------------------------------------------------------
  // -- write keyframe interpolation types
  //------------------------------------------------------

  memset(keyword, 0, 100);
  sprintf(keyword, "interpvolumebounds");
  fout.write((char*)keyword, strlen(keyword)+1);
  fout.write((char*)&m_interpVolumeBounds, sizeof(int));

  memset(keyword, 0, 100);
  sprintf(keyword, "interpcamerapos");
  fout.write((char*)keyword, strlen(keyword)+1);
  fout.write((char*)&m_interpCameraPosition, sizeof(int));

  memset(keyword, 0, 100);
  sprintf(keyword, "interpcamerarot");
  fout.write((char*)keyword, strlen(keyword)+1);
  fout.write((char*)&m_interpCameraOrientation, sizeof(int));

  memset(keyword, 0, 100);
  sprintf(keyword, "interptf");
  fout.write((char*)keyword, strlen(keyword)+1);
  fout.write((char*)&m_interpTF, sizeof(int));

  memset(keyword, 0, 100);
  sprintf(keyword, "interpclipinfo");
  fout.write((char*)keyword, strlen(keyword)+1);
  fout.write((char*)&m_interpClipInfo, sizeof(int));

  memset(keyword, 0, 100);
  sprintf(keyword, "interplightinfo");
  fout.write((char*)keyword, strlen(keyword)+1);
  fout.write((char*)&m_interpLightInfo, sizeof(int));

  //------------------------------------------------------


  memset(keyword, 0, 100);
  sprintf(keyword, "keyframeend");
  fout.write((char*)keyword, strlen(keyword)+1);
}

